package com.eryos.android.cigarettecounter.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import android.util.Log;

/**
 * Project : CigaretteCounter Author : Olivier Combe URL : http://eryos.fr/CigaretteCounter/
 * 
 * Copyright(C)2011 - Olivier Combe
 * 
 * Licensed under the Apache License, Version 2.0(the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 * 
 * @version \$Revision.*\$
 * @author Olivier Combe // Code from: http://lukencode.com/2010/04/27/calling-web-services-in-android-using-httpclient/
 */
public class RestClient {

    /** List of Method Type. */
    public enum RequestMethod {
        /** HTTP GET Method. */
        GET,
        /** HTTP POST Method. */
        POST
    }

    private final List<NameValuePair> params;
    private final List<NameValuePair> headers;

    private final String url;

    private int responseCode;
    private String message;

    private String response;

    /**
     * Create a new Rest Client.
     * 
     * @param urlArg
     *            to request
     */
    public RestClient(final String urlArg) {
        Log.d("CigaretteCounter", getClass().getSimpleName() + " : new RestClient()");

        this.url = urlArg;
        params = new ArrayList<NameValuePair>();
        headers = new ArrayList<NameValuePair>();
    }

    /**
     * Add a param to the request.
     * 
     * @param name
     *            of the param
     * @param value
     *            of the param
     */
    public void addParam(final String name, final String value) {
        params.add(new BasicNameValuePair(name, value));
    }

    /**
     * Add a header to the request.
     * 
     * @param name
     *            of the header
     * @param value
     *            of the header
     */
    public void addHeader(final String name, final String value) {
        headers.add(new BasicNameValuePair(name, value));
    }

    /**
     * Execute a method.
     * 
     * @param method
     *            to execute
     * @throws Exception
     *             in case of error
     */
    public void execute(final RequestMethod method) throws Exception {
        HttpRequestBase request = new HttpPost(url);

        if (RequestMethod.GET.equals(method)) {
            // add parameters
            StringBuffer combinedParams = new StringBuffer("");
            if (!params.isEmpty()) {
                combinedParams.append("?");
                for (NameValuePair p : params) {
                    String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue(), "UTF-8");
                    if (combinedParams.length() > 1) {
                        combinedParams.append("&" + paramString);
                    } else {
                        combinedParams.append(paramString);
                    }
                }
            }

            request = new HttpGet(url + combinedParams);

            // add headers
            for (NameValuePair h : headers) {
                request.addHeader(h.getName(), h.getValue());
            }

        } else if (RequestMethod.POST.equals(method)) {

            request = new HttpPost(url);

            // add headers
            for (NameValuePair h : headers) {
                request.addHeader(h.getName(), h.getValue());
            }

            if (!params.isEmpty()) {
                ((HttpPost) request).setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
            }

        }

        executeRequest(request, url);
    }

    /**
     * Execute the Request.
     * 
     * @param request
     *            to execute
     * @param urlArg
     *            to request
     */
    private void executeRequest(final HttpUriRequest request, final String urlArg) {
        HttpClient client = new DefaultHttpClient();

        HttpResponse httpResponse;

        try {
            httpResponse = client.execute(request);
            responseCode = httpResponse.getStatusLine().getStatusCode();
            message = httpResponse.getStatusLine().getReasonPhrase();

            HttpEntity entity = httpResponse.getEntity();

            if (entity != null) {

                InputStream instream = entity.getContent();
                response = convertStreamToString(instream);

                // Closing the input stream will trigger connection release
                instream.close();
            }

        } catch (ClientProtocolException e) {
            Log.w("CigaretteCounter", getClass().getSimpleName() + " : executeRequest error", e);
            client.getConnectionManager().shutdown();
        } catch (IOException e) {
            Log.w("CigaretteCounter", getClass().getSimpleName() + " : executeRequest error", e);
            client.getConnectionManager().shutdown();
        }
    }

    /**
     * Convert an InputStream into a String.
     * 
     * @param is
     *            InputStream to convert
     * @return String representing inputstream
     */
    private static String convertStreamToString(final InputStream is) {

        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            Log.w("CigaretteCounter", "convertStreamToString", e);
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                Log.w("CigaretteCounter", "convertStreamToString", e);
            }
        }
        return sb.toString();
    }

    /**
     * @return the response
     */
    public String getResponse() {
        return response;
    }

    /**
     * @return the ErrorMessage
     */
    public String getErrorMessage() {
        return message;
    }

    /**
     * @return the responseCode
     */
    public int getResponseCode() {
        return responseCode;
    }
}
